package proj.unions.resource;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.zip.ZipEntry;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
import org.json.JSONException;
import org.json.JSONObject;

import proj.unions.general.L;
import proj.unions.general.OnMyCallBack;
import proj.unions.general.SuperTools;
import proj.unions.general.Text;
import android.accounts.NetworkErrorException;
import android.app.Activity;

public class DownloadGameRes implements Runnable, RMConstDefine {
	private static final int DOWNLOAD_STATUS_SUCCESSFUL = 1;
	private static final int DOWNLOAD_STATUS_NONE = 0;
	private static final int DOWNLOAD_STATUS_FAILURE_IO = -1;
	private static final int DOWNLOAD_STATUS_FAILURE_NET = -2;
	
	private static final int UNZIP_STATUS_SUCCESSFUL = -3;
	private static final int UNZIP_STATUS_NONE = -4;
	private static final int UNZIP_STATUS_FAILURE_IO = -5;
	private static final int UNZIP_STATUS_FAILURE_FILENOTFOUND = -6;

	private Activity mActivity = null;
	private OnMyCallBack mOnMyCallBack = null;

	private String mCDNUrl = null;
	private String mSOUrl = null;
	private String MD5FileUrl = null;

	private int mNewestVersion_res = -1;

	private final static String Versions = "versions.txt";
	private final static String Versions_tp = "versions_tp.txt";

	private long lastSpeed = 0;// 速度
	private long trunkSize = 0;// 块大小
	private boolean isChange = false;

	private int mCode = -1;
	private int mNeedDownloadCount = -1;
	private int mCountFile = -1;
	private float mProcessLen = 0;

	private JSONObject mJson = null;

	private static ConcurrentLinkedQueue<FileData> mLocalFileList = new ConcurrentLinkedQueue<FileData>();
	private static ConcurrentLinkedQueue<FileData> mNetworkFileList = new ConcurrentLinkedQueue<FileData>();
	private static ConcurrentLinkedQueue<FileData> mLocalZIPFileList = new ConcurrentLinkedQueue<FileData>();

	public DownloadGameRes(Activity a, OnMyCallBack l, JSONObject json) {
		mActivity = a;
		mOnMyCallBack = l;
		mJson = json;

		try {
			mNewestVersion_res = mJson.getInt(KEY_NEWEST_VERSION_RES);
			if (ResManager.isUse_ZIP_Download)
				mCDNUrl = json.getString(KEY_CDN_URL) + "zip_pkm/";
			else
				mCDNUrl = json.getString(KEY_CDN_URL) + "pkm/";
			mSOUrl = json.getString(KEY_SO_URL); // so文件地址
			MD5FileUrl = mCDNUrl + Versions; // md5文件地址
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		lastSpeed = 0;
		trunkSize = 0;
		isChange = false;
		mProcessLen = ResManager.mCountPercent;
		clearAll();
	}

	private void clearAll() 
	{
		mLocalFileList.clear();
		mNetworkFileList.clear();
		mLocalZIPFileList.clear();
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		if (mActivity == null || mOnMyCallBack == null) {
			mOnMyCallBack.onReceive("error", 0, null);
			return;
		}

		if (check()) 
		{
			CheckFileList();
			if (beginDownloadAllFile(true))
			{
				if (ResManager.isUse_ZIP_Download)
				{
					if(!beginUnZipAllFile())
					{
						setTimer(false, "");
						clearAll();
						return;
					}
				}
			}
			else
			{
				setTimer(false, "");
				clearAll();
				return;
			}
		}

		//覆写版本文件
		coverVersion();
		mOnMyCallBack.onReceive(Text.getKey("Net_DownloadFinish")/*"资源下载解压完成"*/, 2, null);

		setTimer(false, "");
		clearAll();
		
		mOnMyCallBack.onReceive("yes", 1, null);
	}

	// 检测
	private boolean check() {
		boolean isUpdate = false;
		try {
			isUpdate = mJson.getBoolean(KEY_NEED_UPDATE_RES);

		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return isUpdate;
	}

	// 先下载versions.txt
	private void CheckFileList() 
	{
		L.d("------开始处理version-----");
		InputStream is = null;
		String SDCard_FileName = SuperTools.getInstance().getDownloadResPath()
				+ Versions;// sd卡本地文件列表
		if (!isExistFile(SDCard_FileName)) {
			// sd卡不存在就读assert里面的
			try {
				is = mActivity.getAssets().open(Versions);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else {
			File f = new File(SDCard_FileName);
			try {
				is = new FileInputStream(f);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		String SDCard_FileName_tp = SuperTools.getInstance()
				.getDownloadResPath() + Versions_tp;
		int flag = downloadFile(MD5FileUrl, SDCard_FileName_tp);
		if (flag != DOWNLOAD_STATUS_SUCCESSFUL) {
			// SuperTools.getInstance().showErrorDialog("网络",
			// "下载异常，请联系管理员! Error:" + mCode);
			L.d("下载异常，请联系管理员! Error:" + mCode);
			return;
		}

		InputStream is2 = null;
		File f2 = new File(SDCard_FileName_tp);
		try {
			is2 = new FileInputStream(f2);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		String content = null;
		String content2 = null;
		try {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			int count = 0;
			byte[] buffer = new byte[1024];
			while ((count = is.read(buffer)) != -1) {
				bos.write(buffer, 0, count);
			}
			content = bos.toString();

			ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
			int count2 = 0;
			byte[] buffer2 = new byte[1024];
			while ((count2 = is2.read(buffer2)) != -1) {
				bos2.write(buffer2, 0, count2);
			}
			content2 = bos2.toString();

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		Map<String, String> mLocalFileMap = new HashMap<String, String>();
		String localFileListPart[] = content.split("\n");
		for (int i = 0; i < localFileListPart.length; i++) {
			String str[] = localFileListPart[i].split(",");
			FileData item = new FileData();
			item.name = str[0];
			item.md5 = str[1];
			item.isNeedDownload = false;
			item.downloadCount = 0;
			item.unzipCount = 0;
			// mLocalFileList.add(item);
			mLocalFileMap.put(item.name, item.md5);
		}

		// 对比两个数组
		mOnMyCallBack.onReceive(Text.getKey("Net_CheckRes")/*"资源效验中"*/, 2, null);

		mNeedDownloadCount = 0;
		String networkFileListPart[] = content2.split("\n");
		for (int i = 0; i < networkFileListPart.length; i++) 
		{
			String str[] = networkFileListPart[i].split(",");
			FileData item = new FileData();
			item.name = str[0];
			item.md5 = str[1];
			
			//Versions.txt不做处理
			int index = item.name.lastIndexOf(Versions);
			if(index >= 0)
				continue;
			
			String value = mLocalFileMap.get(item.name);
			if (item.md5.equals(value))
				item.isNeedDownload = false;
			else {
				item.isNeedDownload = true;
				mNeedDownloadCount++;
				mNetworkFileList.add(item);
			}
		}
	}

	private boolean beginDownloadAllFile(boolean _isFirst) 
	{
		if(_isFirst)
		{
			L.d("------开始下载-----");
			L.d("===========资源下载总数为(不包括so):" + mNeedDownloadCount);
		}
		else
		{
			L.d("======有文件出错,需重新下载");
		}
		
		setTimer(true, Text.getKey("Net_DownloadRes")/*"正在下载资源文件"*/);
		mCountFile = 0;
		float retainLength = ResManager.mIamgeTotalength * (1 - mProcessLen) / 5 * 4;
		boolean isNeedReDownload = false;
		
		String localPath = SuperTools.getInstance().getAPKPath();
		localPath = localPath.substring(0, localPath.length() - 1);

		for (FileData item : mNetworkFileList) 
		{
			if (item.isNeedDownload == true) 
			{
				String fileResNetPath = mCDNUrl + item.name.substring(1, item.name.length());
				fileResNetPath = fileResNetPath.replace("\\", "/");
				String fileResLocalPath = localPath + item.name;
				fileResLocalPath = fileResLocalPath.replace("\\", "/");
				mCountFile++;
				item.fullName = fileResLocalPath;
				item.zipName = fileResLocalPath + ".zip";
				item.extensions = "";
				int flag = -1;
				if (ResManager.isUse_ZIP_Download) // 是否使用zip下载
					flag = downloadFile(fileResNetPath + ".zip", item.zipName);
				else
					flag = downloadFile(fileResNetPath, item.fullName);
				
				item.downloadCount++;
				if (flag == DOWNLOAD_STATUS_SUCCESSFUL) 
				{
					L.d("文件 " + mCountFile + " :" + item.name + "下载成功");
					
					item.isNeedDownload = false;
					mLocalZIPFileList.add(item);
					
					float ret = (1.0f / (float) mNeedDownloadCount) * retainLength;
					ResManager.mCountPercent += (ret / ResManager.mIamgeTotalength);
				}
				else 
				{
					//需要重新下载
					isNeedReDownload = true;
					if(item.downloadCount < 2)
						L.d("文件 " + mCountFile + " :" + item.name + "下载不成功");
					else
						L.d("文件 " + mCountFile + " :" + item.name + "再次下载不成功");
					
					if(item.downloadCount > 10)
					{
						L.d("文件 " + mCountFile + " :" + item.name + "这文件没救了");
						SuperTools.getInstance().showErrorDialog(Text.getKey("Net")/*"网络"*/, Text.getKey("Net_CallManager_ErrorResD")/*"下载资源失败，请联系管理员!"*/);
						return false;
					}
				}

				// String content = "正在下载资源文件" + " (" + mCountFile + "/" +
				// mNeedDownloadCount + ")";
			}
		}
		//需要重新下载
		if(isNeedReDownload)
		{
			try {
				Thread.sleep(500);
				L.d("=====稍等0.5秒=====");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return beginDownloadAllFile(false);
		}
		return true;
	}

	private boolean beginUnZipAllFile() 
	{
		L.d("------开始解压-----");
		setTimer(true, Text.getKey("Local_UnZipRes")/*"正在解压资源文件"*/);
		
		float retainLength = ResManager.mIamgeTotalength * (1 - mProcessLen) / 5;
		
		int count = 1;	//计数
		while (true) 
		{
			if (mLocalZIPFileList.isEmpty()) 
				break;
			
			FileData data = mLocalZIPFileList.poll();
			if (data == null) {
				L.d("文件: data == null");
				continue;
			}
			String[] str = data.fullName.split("/");
			if (data.fullName.endsWith("/")) {
				L.d("文件:" + data.name + "   str.length < 1:"
						+ str.length);
				continue;
			}
			
			String emptyPath = data.fullName.substring(0, data.fullName.lastIndexOf("/") + 1);
			int flag = unzipFile(data.zipName, emptyPath);
			data.unzipCount++;
			if (flag == UNZIP_STATUS_SUCCESSFUL) 
			{
				L.d("文件 " + count + " :" + data.name + "解压成功");
				// 干掉zip文件
				SuperTools.getInstance().deleteFile(data.zipName);
				count++;
				
				float ret = (1.0f / (float) mNeedDownloadCount) * retainLength;
				ResManager.mCountPercent += (ret / ResManager.mIamgeTotalength);
			}
			 else
			 {
				if(data.unzipCount < 2)
					L.d("文件:" + data.name + "解压不成功");
				else
					L.d("文件:" + data.name + "再次解压不成功");
				if(data.unzipCount > 10)
				{
					L.d("文件 " + count + " :" + data.name + "这文件没救了");
					SuperTools.getInstance().showErrorDialog(Text.getKey("Net")/*"网络"*/, Text.getKey("Local_CallManager_ErrorResU")/*"解压资源失败，请联系管理员!"*/);
					return false;
				}
				mLocalZIPFileList.add(data);//将文件再次添加回去
			 }
		}
		
		return true;
	}

	private void coverVersion() 
	{
		L.d("------重写version-----");
		SuperTools.getInstance().writeLocalFile(KEY_CLIENT_VERSION_RES, "" + mNewestVersion_res);
		// 覆盖versions_tp.txt文件
		// 改回正常的名字
		String SDCard_FileName_tp = SuperTools.getInstance()
				.getDownloadResPath() + Versions_tp;
		String SDCard_FileName = SuperTools.getInstance().getDownloadResPath()
				+ Versions;
		SuperTools.deleteFile(new File(SDCard_FileName));
		File oldf = new File(SDCard_FileName_tp);
		File newf = new File(SDCard_FileName);
		oldf.renameTo(newf);
	}

	private int downloadFile(String url, String name)
	{
		try {
			byte[] buffer = new byte[2048];
			HttpGet getMethod = new HttpGet(url);
			HttpClient httpClient = new DefaultHttpClient();
			
			httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);//建立http时间30
			httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 8000);//读写时间限制8秒
			
			HttpResponse response = httpClient.execute(getMethod);

			long fileSize = response.getEntity().getContentLength();

			int byteReaded = 0;
			int curSize = 0;

			int code = response.getStatusLine().getStatusCode();
			if (code == 200) {
				InputStream is = response.getEntity().getContent();
				File f = new File(name);
				if (f.exists())
					f.delete();
				if (!f.getParentFile().exists()) {
					f.getParentFile().mkdirs();
				}
				f.createNewFile();
				FileOutputStream fos = new FileOutputStream(f);
				do {
					try {
						byteReaded = is.read(buffer);
						curSize += byteReaded;
						trunkSize += byteReaded;
						float curProcess = ((float) curSize / (float) fileSize * 100);
						int count = (int) (curProcess / 2);
						if (isChange) {
							isChange = false;
							lastSpeed = trunkSize / 1024;
							trunkSize = 0;
						}
						String curName = name
								.substring(name.lastIndexOf("/") + 1);
//						String content = "正在更新资源:" + mNewestVersion_res
//								+ " 文件:" + curName + " (" + mCountFile + "/"
//								+ mNeedDownloadCount + ")";
						// mOnMyCallBack.onReceive(content, 2, null);
					} catch (IOException e) {
						try {
							throw new NetworkErrorException(e);
						} catch (NetworkErrorException e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
					}
					if (byteReaded > 0) {
						fos.write(buffer, 0, byteReaded);
					}
					fos.flush();
				} while (byteReaded != -1);
				fos.close();

				return DOWNLOAD_STATUS_SUCCESSFUL;
			} else
				mCode = code;
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			L.d("download:" + e.getMessage());
			return DOWNLOAD_STATUS_FAILURE_NET;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			L.d("download:" + e.getMessage());
			return DOWNLOAD_STATUS_FAILURE_IO;
		}

		return DOWNLOAD_STATUS_NONE;
	}

	// 解压
	public static int unzipFile(String tpFileName, String tpFilePath) {
		String srcFileName = tpFileName;
		File existFile = new File(srcFileName);
		if (!existFile.exists()) {
			// zip文件不存在
			L.d(" ******* 文件:" + tpFileName + " 文件不存在");
			return UNZIP_STATUS_FAILURE_FILENOTFOUND;
		}
		try {
			FileInputStream stream = new FileInputStream(srcFileName);
			try {
				java.util.zip.ZipInputStream inZip = new java.util.zip.ZipInputStream(
						stream);
				ZipEntry zipEntry = inZip.getNextEntry();

				while (zipEntry != null) {
					String targetFileName = tpFilePath + zipEntry.getName();
					String TargetFileName_tp = tpFilePath + zipEntry.getName() + "_tp";
					File tpTargetFileName = new File(TargetFileName_tp);
					if (tpTargetFileName.exists())
						tpTargetFileName.delete();

					byte[] buffer = new byte[10240];
					try {
						FileOutputStream out = new java.io.FileOutputStream(
								TargetFileName_tp);
						int len;
						while ((len = inZip.read(buffer)) != -1) {
							out.write(buffer, 0, len);
							out.flush();
						}

						out.close();

						// 改回正常的名字
						File oldf = new File(TargetFileName_tp);
						File newf = new File(targetFileName);
						if (newf.exists())
							newf.delete();
						oldf.renameTo(newf);

					} catch (FileNotFoundException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}

					zipEntry = inZip.getNextEntry();
				}
				
				return UNZIP_STATUS_SUCCESSFUL;

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				L.d("download:" + e.getMessage());
				return UNZIP_STATUS_FAILURE_IO;
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			L.d("download:" + e.getMessage());
			return UNZIP_STATUS_FAILURE_FILENOTFOUND;
		}
//		return UNZIP_STATUS_NONE;
	}

	private static Thread mTimerThread = null;
	private static String mTimerString = null; 
	//定时去处理下方文字
	private void setTimer(boolean _isOpen, String _content)
	{
		mTimerString = _content;
		if(mTimerThread == null)
			mTimerThread = new Thread(new Runnable() {
				
				@Override
				public void run() {
					// TODO Auto-generated method stub
					while (true)
					{
						if(Thread.currentThread().getName().equals("Over"))
							break;
						try {
							Thread.sleep(400);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						
						String ret = mTimerString;
						if(!mTimerString.equals(""))
							ret += SuperTools.getInstance().getSomeThing(false);
						mOnMyCallBack.onReceive(ret, 2, null);
					}
					L.d("===== end DownloadGameRes Timer");
				}
			});
		
		if(_isOpen && mTimerThread != null)
		{
			SuperTools.getInstance().getSomeThing(true);
			if(!mTimerThread.isAlive())
				mTimerThread.start();
		}
		if(!_isOpen && mTimerThread != null)
		{
			mTimerThread.setName("Over");
			mTimerThread = null;
		}
	}
	
	private boolean isExistFile(String name) {
		File f = new File(name);
		return f.exists();
	}

	public class FileData {
		String name;
		String md5;
		boolean isNeedDownload;
		int downloadCount;
		int unzipCount;

		String fullName;
		String zipName;
		String extensions;
	}

}
